package com.hlf.modules.wechat.controller;

import com.hlf.common.constants.Constants;
import com.hlf.common.utils.PropertieUtil;
import com.hlf.common.utils.XmlUtils;
import com.hlf.common.utils.wx.WeixinMessageDigest;
import com.hlf.common.utils.wx.WxUserInfo;
import com.hlf.common.utils.wx.WxUtils;
import com.hlf.common.validator.Assert;
import com.hlf.modules.merchant.order.service.OrderService;
import com.hlf.modules.wechat.model.Customer;
import com.hlf.modules.wechat.model.OfficialAccount;
import com.hlf.modules.wechat.model.UserOfficial;
import com.hlf.modules.wechat.service.CustomerService;
import com.hlf.modules.wechat.service.OfficialAccountService;
import com.hlf.modules.wechat.service.UserOfficialService;
import com.hlf.modules.wechat.service.WeChatService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;


/**
 * 微信表现层控制类
 *
 * @author shuliangxing
 * @date 2017年4月21日 下午12:00:12
 */
@RestController
@RequestMapping("wechat")
public class WeChatController {

    private final static Logger logger = LoggerFactory.getLogger(WeChatController.class);


    @Autowired
    private OfficialAccountService officialAccountService;
    @Autowired
    private UserOfficialService userOfficialService;
    @Autowired
    private CustomerService customerService;
    @Autowired
    private PropertieUtil propertieUtil;
    @Autowired
    private WeChatService weChatService;
    @Autowired
    private OrderService orderService;

    @GetMapping(produces = "text/plain;charset=utf-8")
    public String authGet(
            @RequestParam(name = "signature",
                    required = false) String signature,
            @RequestParam(name = "timestamp",
                    required = false) String timestamp,
            @RequestParam(name = "nonce", required = false) String nonce,
            @RequestParam(name = "echostr", required = false) String echostr) {

        logger.info("\n接收到来自微信服务器的认证消息：[{}, {}, {}, {}]", signature,
                timestamp, nonce, echostr);
        return echostr;
    }


    /**
     * 微信推送
     *
     * @param request
     * @return
     * @author shuliangxing
     * @date 2017年4月21日 下午4:33:00
     */
    @PostMapping(produces = "application/xml; charset=UTF-8")
    public String eventPush(HttpServletRequest request) {
        logger.info("微信推送开始==========>");

        String signature = request.getParameter("signature");
        // 随机字符串
        String echostr = request.getParameter("echostr");
        // 时间戳
        String timestamp = request.getParameter("timestamp");
        // 随机数
        String nonce = request.getParameter("nonce");
        logger.info("微信推送验证参数 signature={}, echostr={}, timestamp={}, nonce={}", signature, echostr, timestamp, nonce);

        String result = echostr;
        if (StringUtils.isBlank(result)) {
            result = "success"; // 如果直接回复空字符串微信服务器配置验证不通过
        }
        try {
            // SHA1加密
            WeixinMessageDigest wxDigest = WeixinMessageDigest.getInstance();
            boolean bValid = wxDigest.validate(signature, timestamp, nonce);
            // 确认请求来至微信
            if (bValid) {
                logger.info("微信推送验证通过");

                ServletInputStream stream = request.getInputStream();
                Map<String, String> requestMap = XmlUtils.parseXml(request.getInputStream());
                logger.info("微信推送数据={}", requestMap);

                // 发送方帐号（open_id）
                String openId = requestMap.get("FromUserName");
                // 公众号原始id（开发者微信号）
                String originalId = requestMap.get("ToUserName");
                // 消息类型
                String msgType = requestMap.get("MsgType");
                // 事件类型，subscribe(订阅)、unsubscribe(取消订阅)、详见微信文档...
                String event = requestMap.get("Event");
                // 事件KEY值
                String eventKey = requestMap.get("EventKey");

                if (openId == null) {
                    return result;
                }

                // 查询公众号
                OfficialAccount oa = officialAccountService.selectByOriginalId(originalId);
                if (oa == null) {
                    logger.error("查询不到公众号信息，公众号原始id={}", originalId);
                    return result;
                }
                // 微信用户信息
                WxUserInfo wxUserInfo = WxUtils.getWxUserInfo(openId, oa.getToken());
                logger.info("用户信息{}", wxUserInfo);
                if (wxUserInfo == null) {
                    logger.error("获取微信用户信息失败！");
                    return result;
                }

                // 查询用户和公众号关联关系
                UserOfficial uo = userOfficialService.selectByOpenIdOffAccId(openId, String.valueOf(oa.getId()));
                // 用户信息
                Customer customer = customerService.queryByOpenId(wxUserInfo.getOpenid());

                if (customer == null) {
                    customerService.insert(wxUserInfo, null);
                } else if (!"unsubscribe".equals(event)) {
                    customerService.updateByOpenId(wxUserInfo, customer);
                }

                if (uo == null) {
                    UserOfficial addUo = new UserOfficial();
                    addUo.setUserId(customer.getCustomerId());
                    addUo.setOfficialAccountId(String.valueOf(oa.getId()));
                    addUo.setOpenId(openId);
                    addUo.setFollowStatus(Constants.IS_SUBSCRIBE);
                    addUo.setLastUpdateBy(0L);
                    logger.info("用户存在，但用户和公众号关联关系不存在，新增关联关系 UserOfficialRel={}", addUo);
                    userOfficialService.insertAll(addUo);
                }

                // 非事件推送暂不处理
                if (!"event".equals(msgType)) {
                    logger.info("非事件推送暂不处理，msgType={}", msgType);
                    return result;
                } else {
                    // 订阅事件
                    if ("subscribe".equals(event)) {
                        logger.info("订阅事件,更新用户与公众号状态为已订阅,CustomerId={},officialAccountId={}", customer.getCustomerId(), oa.getId());
                        // 更新用户和公众号关联表状态为已订阅
                        userOfficialService.doSubscribe(customer.getCustomerId(), String.valueOf(oa.getId()));
                        String msg = propertieUtil.getPropertie("WECHAT_FOCUS_EVENT_MSG");
                        WxUtils.pushMessage(oa.getToken(),openId,msg);
                    }
                    // 取消订阅/*
                    else if ("unsubscribe".equals(event)) {
                        logger.info("取消订阅事件,更新用户与公众号状态为未定阅,CustomerId={},officialAccountId={}", customer.getCustomerId(),
                                oa.getId());
                        // 更新用户和公众号关联表状态为取消订阅
                        userOfficialService.doUnSubscribe(customer.getCustomerId(), String.valueOf(oa.getId()));
                    } else {
                        logger.info("其它事件\"{}\"暂未处理", event);
                    }
                }

            } else {
                logger.error("微信推送验证失败,signature={},echostr={},timestamp={},nonce={}", signature, echostr, timestamp,
                        nonce);
            }
        } catch (Exception e) {
            logger.error("微信推送异常", e);
        }
        logger.info("<==========微信推送结束");
        return result;

    }

    /**
     * Oauth2网页授权回调
     * http://order.halopay.cn/?abc=123&ccc=111&code=021UDNaC1ClFm20frpbC10mQaC1UDNaf&state=STATE
     */
    @RequestMapping("oauth2/{tableId}")
    public void Oauth2(@PathVariable(value = "tableId", required = false) String tableId,
                       @RequestParam(value = "code", required = false) String code,
                       HttpServletResponse response) throws IOException {
        Assert.isNull(tableId, "抱歉,未找到该餐厅!");

        Map<String, Object> map = weChatService.Oauth2Logo(tableId, code);
        //返回一个token
        String s = String.valueOf(map.get("redirect")) + "?token=" + map.get("token");
        response.sendRedirect(s);
    }


}
